casbin最牛逼的权限管理 您所在的位置:网站首页 form role casbin最牛逼的权限管理

casbin最牛逼的权限管理

#casbin最牛逼的权限管理| 来源: 网络整理| 查看: 265

先上链接casbin官网

casbin能做什么? 支持多种编程语言Go/Java/Node/PHP/Python/.NET/Rust,一次学习多处运用 支持自定义请求格式,默认格式(subject,object,action) 具有访问控制模型model和策略policy两个核心概念 支持RBAC中的多层继承,不仅subject有角色,object也可以有角色 支持内置的超级用户,例如root或admin,超级用户可以执行任何操作而无需显式的权限声明 支持多种内置的操作符,如 keyMatch,方便对路径式的资源进行管理,如 /foo/bar 可以映射到 /foo* Casbin 不能做什么? 身份认证 authentication(即验证用户的用户名、密码),casbin只负责访问控制。应该有其他专门的组件负责身份认证,然后由casbin进行访问控制,二者是相互配合的关系。 管理用户列表或角色列表。 Casbin 认为由项目自身来管理用户、角色列表更为合适, 用户通常有他们的密码,但是 Casbin 的设计思想并不是把它作为一个存储密码的容器。 而是存储RBAC方案中用户和角色之间的映射关系 快速开始

Casbin使用配置文件来设置访问控制模式。

它有两个配置文件,model.conf和policy.csv。 其中,model.conf存储了访问模型,policy.csv存储了特定的用户权限配置。 Casbin的使用非常精炼。 基本上,我们只需要一个主要结构:enforcer。 当构建这个结构时,model.conf和policy.csv将被加载

mkdir demo && cd demo && go mod init github.com/51op/go-sdk-demo go get github.com/casbin/casbin/v2 复制代码 创建model模型文件model.conf [request_definition] r = sub, obj, act [policy_definition] p = sub, obj, act [matchers] m = r.sub == p.sub && r.obj == p.obj && r.act == p.act || r.sub == "root" #只要访问主体是root一律放行。 [policy_effect] e = some(where (p.eft == allow)) 复制代码

上面模型文件规定了权限由sub,obj,act三要素组成,只有在策略列表中有和它完全相同的策略时,该请求才能通过。匹配器的结果可以通过p.eft获取,some(where (p.eft == allow))表示只要有一条策略允许即可

创建策略控制文件policy.csv p, demo , /user, write #demo用户对/user有write权限 p, demo , /order, read #demo用户对/order有read权限 p, demo1 , /user/userlist,read #demo1用户对/user/userlist有read权限 p, demo2 , /order/orderlist,read #demo2用户对/order/orderlist有read权限 复制代码 检查权限 import ( "fmt" "github.com/casbin/casbin/v2" gormadapter "github.com/casbin/gorm-adapter/v3" _ "github.com/go-sql-driver/mysql" "log" "testing" ) func CheckPermi(e *casbin.Enforcer ,sub,obj,act string) { ok, err := e.Enforce(sub, obj, act) if err != nil { return } if ok == true { fmt.Printf("%s CAN %s %s\n", sub, act, obj) } else { fmt.Printf("%s CANNOT %s %s\n", sub, act, obj) } } func TestCasBin( t *testing.T) { e, err := casbin.NewEnforcer("./model.conf", "./policy.csv") if err !=nil{ log.Fatalf("NewEnforecer failed:%v\n", err) } //基本权限设置 CheckPermi(e, "demo", "/user", "read") CheckPermi(e, "demo", "/order", "write") CheckPermi(e, "demo1", "/user/userlist", "read") CheckPermi(e, "demo1", "/order/orderlist", "write") } 复制代码

可通过官网的编辑器直接运行查看结果,【直达链接】

image-20211201134847206 实战项目 参考

有些代码未做抽取勿喷

目录结构如下: dnspod/ ├── api │   ├── casbiniapi.go │   ├── internal │   │   └── model │   │   └── casbin.go ├── config │   ├── config.json │   ├── config.yaml │   └── model.conf ├── common │   ├── global.go ├── Dockerfile ├── docs │   ├── docs.go │   ├── swagger.json │   └── swagger.yaml ├── go.mod ├── go.sum ├── main.go ├── router │   ├── handler │   │   └── func.go │   └── route.go 复制代码 首先在configs目录下创建model.conf`文件,写入如下代码: #此文件存储访问模型 [request_definition] r = sub, obj, act [policy_definition] p = sub, obj, act [role_definition] g = _, _ [policy_effect] e = some(where (p.eft == allow)) [matchers] m = r.sub == p.sub && r.obj == p.obj || ParamsMatch(r.obj,p.obj) && r.act == p.act 复制代码 在api/internal/model目录下,创建casbin.go文件 package model import ( "dnspod/common" _ "dnspod/common" "log" ) type CasinoModel struct { PType string `gorm:"column:p_type" json:"p_type" form:"p_type" description:"策略类型"` RoleId string `gorm:"column:v0" json:"role_id" form:"v0" description:"角色id"` Path string `gorm:"column:v1" json:"path" form:"v1" description:"api路径"` Method string `gorm:"column:v2" json:"method" form:"v2" description:"方法"` } func(c *CasinoModel) TableName() string { return "casbin_rule" } func ( c *CasinoModel) AddPolicy() error { if ok,_:=common.CasBin.AddPolicy(c.RoleId,c.Path,c.Method);ok==false{ return common.JsonResponse(100,"增加策略失败") } return common.JsonResponse(200,"增加策略成功") } 复制代码 在common/目录下的global.go文件中增加如下: func InitCasbinDB() *casbin.Enforcer { dsn:=fmt.Sprintf("%s:%s@tcp(%s)/",cfg.MySQL.Username,cfg.MySQL.Password,cfg.MySQL.Host) adapter, _ := gormadapter.NewAdapter("mysql", dsn,) CasBin, _ = casbin.NewEnforcer(cfg.CasBin.FilePath, adapter) CasBin.AddFunction("ParamsMatch",ParamsMatchFunc) CasBin.LoadPolicy() return CasBin } func ParamsMatch(fullNameKey1 string,key2 string) bool { key1 := strings.Split(fullNameKey1, "?")[0] return util.KeyMatch2(key1,key2) } //注册func到casbin func ParamsMatchFunc(args ...interface{})(interface{},error) { name1 := args[0].(string) name2 := args[1].(string) return ParamsMatch(name1, name2), nil } 复制代码

在router/下的route.go增加请求

common.InitCasbinDB() //初始化 InitCasbinDB //Casbin权限认证 authGroup:=router.Group("/api/v1/auth") { authGroup.POST("/addPolicy",handler.AddPolicy) } 复制代码

router/handler目录下的func.go中增加AddPolicy

//Casbin 权限管理 type CasbinInfo struct { Path string `json:"path" form:"path"` Method string `json:"method" form:"method"` } type CasbinCreateRequest struct { RoleId string `json:"role_id" form:"role_id" description:"角色ID"` CasbinInfos []CasbinInfo `json:"casbin_infos" description:"权限模型列表"` } func AddPolicy(c *gin.Context ) { log.Printf("==========") var params CasbinCreateRequest c.ShouldBind(¶ms) for _, v := range params.CasbinInfos { log.Println(params.RoleId, v.Path, v.Method) err := api.AddPolicyApi(params.RoleId, v.Path, v.Method) if err != nil { // c.JSON(http.StatusOK,gin.H{ // "res":"bad", // }) } } c.JSON(http.StatusOK,gin.H{ "res":"ok", }) } 复制代码 在api/目录下创建casbiniapi.go文件 package api import "dnspod/api/internal/model" func AddPolicyApi(roleId string, path, method string) error { p:=model.CasinoModel{ PType: "p", RoleId: roleId, Path: path, Method: method, } p.AddPolicy() return nil } 复制代码

最后启动项目

验证

image-20211119145105282

查看mysql库里数据就有了

image-20211119145133791

权限验证通过后处理正常业务逻辑

增加访问入口

authGroup.GET("/testPolicy",common.CasbinMiddleware(),handler.TestListPolicics) 复制代码

测试业务逻辑

func TestListPolicics(c *gin.Context) { c.JSON(http.StatusOK,common.Reponse{200,"权限通过正常的业务逻辑",""}) } 复制代码

增加casbin中间件

//casbin中间件 func CasbinMiddleware() gin.HandlerFunc { return func(c *gin.Context) { r:=NewResponseContext(c) path:=c.Request.URL.RequestURI() // method:=c.Request.Method log.Println(path,method) //验证url权限 roleId:="admin" ok, _ := CasBin.Enforce(roleId, path, method) if ok { c.Next() }else { c.Abort() r.ResponseContextMsg("很遗憾,权限验证没有通过") return } } } 复制代码

在当前mysql库中没有 p /api/v1/auth/testPolicy GET策略的时候执行这个api会返回没有权限

image-20211122154043079

添加api/v1/auth/addPolicy权限

image-20211122154355854

然后在执行/api/v1/auth/testPolicy 这个接口已经有权限了

image-20211122154818565

查询角色下的权限

authGroup.POST("/listPolicy",handler.GetListPolicy) //获取当前用户下的所有策略 复制代码 func GetListPolicy( c *gin.Context) { params:=CasbinRequestRoleId{} c.ShouldBind(¶ms) res:=api.ListPolicyApiByRoleId(params.RoleId) log.Println(res) c.JSON(http.StatusOK,common.Reponse{200,"获取成功",res}) } 复制代码 func ListPolicyApiByRoleId(roleId string) [][]string { r:=model.CasinoModel{RoleId: roleId} return r.ListPolicyByRoleId(roleId) } 复制代码

image-20211123104815687

基于RBAC权限认证

model模型中要修匹配器如下:

//使用keyMatch函数,这种情况下才能匹配传递不通参数的用户来匹配不同用户的权限,/api/v1/auth/testPolicy/user1、/api/v1/auth/testPolicy/user2 [matchers] m = g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && r.act == p.act 复制代码 增加角色

分为给用户分配单一角色、给用户分配多个角色

//给单一用户分配单一角色 func (c *CasinoModel) AddRoleForUser(user string,roles string) error { if ok, _ := common.CasBin.AddRoleForUser(user, roles);!ok{ return errors.New("给用户分配单一角色失败") } return nil } //给单一用户分配多个角色 func (c *CasinoModel) AddRolesForUser(user string,roles []string) error { if ok, _ := common.CasBin.AddRolesForUser(user, roles);!ok{ return errors.New("数据库中已经对应的roles策略") } return nil } 复制代码

在目录./router/handler/func.go中增加路由

type UserRoleInfo struct { UserName string `json:"user_name"` RoleName string `json:"role_name"` } func AddRoleUser(c *gin.Context) { u:= UserRoleInfo{} c.ShouldBind(&u) if err:=api.AddRoleForUserApi(u.UserName,u.RoleName);err !=nil{ common.ErrorResp(c,http.StatusInternalServerError,"给用户增加role失败") return } common.SuccessResp(c,"给用户增加role成功") } //给单一用户分配多个角色 type RolesInfoRequest struct { UserName string `json:"user_name"` RoleName []string `json:"role_name"` } func AddRolesUser(c *gin.Context) { ro:= RolesInfoRequest{} err:=c.ShouldBind(&ro) if err !=nil { panic(err) } if err:=api.AddRolesForUserApi(ro.UserName,ro.RoleName);err!=nil{ common.ErrorResp(c,http.StatusInternalServerError,"给用户分配多个roles失败") return } common.SuccessResp(c,"给用户分配多个roles成功") } 复制代码

router/route.go中增加路由

authGroup.POST("/AddRoleUser",handler.AddRoleUser) authGroup.POST("/AddRolesUser",handler.AddRolesUser) 复制代码 验证RBAC image-20211201103357034

查看数据库,就有了相对应的一条记录

image-20211201103428792 image-20211201103618305 image-20211201103652583

给角色member分配测试uri的权限

image-20211201141557464

查看数据库已有相对应的记录

image-20211201141618925

分别请求/api/v1/auth/testPolicy/user1和/api/v1/auth/testPolicy/user2

user1验证未通过

user2通过

image-20211201142218138 image-20211201142232525

【关注我】持续更新ing。。。。。。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有